package org.rainbowinverted.charging.device.connect.bl.server.handler;

import cn.hutool.core.util.HexUtil;
import com.dix.codec.bkv.BKV;
import com.dix.codec.bkv.KV;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.rainbowinverted.charging.common.core.StringPadUtils;
import org.rainbowinverted.charging.device.api.operation.constants.DeviceChargeControlStatusConstants;
import org.rainbowinverted.charging.device.connect.bl.server.message.in.BlDeviceChargeControlIn;
import org.rainbowinverted.charging.device.connect.bl.server.message.out.BlDeviceChargeControlOut;
import org.rainbowinverted.charging.device.connect.bl.server.message.out.BlDeviceChargeStandardOut;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * @author huaiping
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class BlChargeControlHandler extends BlAbstractHandler<BlDeviceChargeControlIn, BlDeviceChargeControlOut> {
    /**
     * 设备写入最大余额
     * 设备接收金额最大2个字节
     */
    private final static int DEVICE_WRITE_MAX_BALANCE = (2 << 15) - 1;

    @Override
    public void write(BlDeviceChargeControlOut message, BKV bkv) {
        // 可用余额
        String balanceOfVoice = String.format("%08x", message.getBalanceOfVoice());
        String balance = String.format("%04x", message.getBalance() > DEVICE_WRITE_MAX_BALANCE ? DEVICE_WRITE_MAX_BALANCE : message.getBalance());
        // 电枪号
        bkv.add(0x08, message.getGunNo());
        // 类型：0x01-主动（如扫码）；0x02-被动（如刷卡）
        bkv.add(0x47, 0x01);
        // 开关：0-关，1-开
        bkv.add(0x13, message.getOnOff() ? 0x01 : 0x00);
        // 语音播报类型：1-在线储值卡，2-在线包月卡
        bkv.add(0x70, 0x01);
        // 余额转换为十六进制字符串，位数必须填满，不足补0
        // 语音播报卡余额：1-储值卡，单位0.01元；2-包月卡，单位0.01小时
        bkv.add(0x71, HexUtil.decodeHex(balanceOfVoice));
        // 充电模式：4-汽车充，服务费
        bkv.add(0x12, 0x04);
        // 服务费收取模式：0-按时收取，1-按电量收取
        // 推荐使用 0x01，设备提供方说按时收取不在维护
        bkv.add(0x80, 0x01);
        // 服务费起步价
        bkv.add(0x81, HexUtil.decodeHex("0000"));
        // 服务费封顶价
        bkv.add(0x82, 0xffff);
        // 服务费每档信息：(2时间【1字节小时1字节分钟】+2电费单价 +2服务费单价) 6 + 6 + ... + 6
        String chargeStandardsHex = convertChargeStandardsToHex(message.getChargeStandards());
        bkv.add(0x83, HexUtil.decodeHex(chargeStandardsHex));
        // 服务费模式支付金额
        bkv.add(0x88, HexUtil.decodeHex(balance));
        // 服务费档位数：最多10档
        bkv.add(0x89, HexUtil.decodeHex(StringPadUtils.leftPad(Integer.toHexString(chargeStandardsHex.length() / 12), "0", 2)));
        createFuture(getSerialNo(bkv));
    }

    @Override
    public void read(ChannelHandlerContext channelHandlerContext, BKV bkv) {
        Long serialNo = getSerialNo(bkv);
        byte ack = getAck(bkv);
        // 充电枪号
        short gunNo = Short.parseShort(HexUtil.encodeHexStr(bkv.get(0x08).getValue()), 16);
        // 充电单号
        Integer chargeNo = Integer.parseInt(HexUtil.encodeHexStr(bkv.get(0x0a).getValue()), 16);
        BlDeviceChargeControlIn chargeControlDTO = BlDeviceChargeControlIn.of(ack == 0x01, gunNo, chargeNo, DeviceChargeControlStatusConstants.UN_KNOW);
        // 控制码 0-成功；1-未插枪；2-车端CP电压错误，操作失败才有值
        chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.CONTROL_SUCCESS);
        KV kv0x97 = bkv.get(0x97);
        if (Objects.nonNull(kv0x97)) {
            byte controlCode = Byte.parseByte(HexUtil.encodeHexStr(kv0x97.getValue()), 16);
            switch (controlCode) {
                case 0x00:
                    chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.CONTROL_SUCCESS);
                    break;
                case 0x01:
                    chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.UN_INSERTED);
                    break;
                case 0x02:
                    chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.TERMINAL_CP_VOLTAGE_ERROR);
                    break;
                case 0x03:
                    chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.EMERGENCY_BUTTON_OPEN);
                    break;
                default:
                    chargeControlDTO.setControlStatus(DeviceChargeControlStatusConstants.UN_KNOW);
                    break;
            }
        }
        complete(serialNo, chargeControlDTO);
        log.info("device charge control result: {}", chargeControlDTO);
    }

    /**
     * 将收费标准转换为十六进制
     * 目标格式：(2时间【1字节小时1字节分钟】+2电费单价 +2服务费单价)      6+6+……+6
     * 设备默认从00:00开始，故不需要传开始时段
     *
     * @param chargeStandardsList 收费标准列表
     * @return {@link String}
     */
    private String convertChargeStandardsToHex(List<BlDeviceChargeStandardOut> chargeStandardsList) {
        if (chargeStandardsList == null || chargeStandardsList.isEmpty()) {
            return "";
        }
        StringBuilder hexBuilder = new StringBuilder();
        for (BlDeviceChargeStandardOut chargeStandard : chargeStandardsList) {
            hexBuilder.append(String.format("%02x", chargeStandard.getEndTime().getHour()));
            hexBuilder.append(String.format("%02x", chargeStandard.getEndTime().getMinute()));
            // 电费
            hexBuilder.append(String.format("%04x", chargeStandard.getElectricityFee()));
            // 服务费
            hexBuilder.append(String.format("%04x", chargeStandard.getServiceFee()));

        }
        return hexBuilder.toString();
    }
}
